import { NDatePicker } from "naive-ui";
import type {
  DatePickerProps,
  DatePickerClearSlotProps,
  DatePickerNowSlotProps,
  DatePickerConfirmSlotProps,
  DatePickerInst,
} from "naive-ui";

import type { BaseComponentType, OmitHTMLAttributes } from "../types";
import { getSlotsDom } from "../utils";
export type DatePickerFactoryConstructorType = {
  props?: DatePickerProps;
  attrs?: OmitHTMLAttributes<"onChange">;
  dateIconSlot?: BaseComponentType;
  footerSlot?: BaseComponentType;
  nextMonthSlot?: BaseComponentType;
  nextYearSlot?: BaseComponentType;
  prevMonthSlot?: BaseComponentType;
  prevYearSlot?: BaseComponentType;
  separatorSlot?: BaseComponentType;
  clearSlot?: (v?: DatePickerClearSlotProps) => BaseComponentType;
  nowSlot?: (v?: DatePickerNowSlotProps) => BaseComponentType;
  confirmSlot?: (v?: DatePickerConfirmSlotProps) => BaseComponentType;
};
export class DatePickerFactory {
  private attrs: OmitHTMLAttributes<"onChange"> = {};
  private props: DatePickerProps = {};
  private dateIconSlot: BaseComponentType = null;
  private footerSlot: BaseComponentType = null;
  private nextMonthSlot: BaseComponentType = null;
  private nextYearSlot: BaseComponentType = null;
  private prevMonthSlot: BaseComponentType = null;
  private prevYearSlot: BaseComponentType = null;
  private separatorSlot: BaseComponentType = null;

  private clearSlot: (v?: DatePickerClearSlotProps) => BaseComponentType = () =>
    null;

  private nowSlot: (v?: DatePickerNowSlotProps) => BaseComponentType = () =>
    null;

  private confirmSlot: (v?: DatePickerConfirmSlotProps) => BaseComponentType =
    () => null;

  private domRef: DatePickerInst | null = null;

  constructor(data?: DatePickerFactoryConstructorType) {
    if (data?.props) this.setProps(data.props);
    if (data?.attrs) this.setAttrs(data.attrs);
    if (data?.dateIconSlot) this.setDateIcon(data.dateIconSlot);
    if (data?.footerSlot) this.setFooter(data.footerSlot);
    if (data?.nextMonthSlot) this.setNextMonth(data.nextMonthSlot);
    if (data?.nextYearSlot) this.setNextYear(data.nextYearSlot);
    if (data?.prevMonthSlot) this.setPrevMonth(data.prevMonthSlot);
    if (data?.prevYearSlot) this.setPrevYear(data.prevYearSlot);
    if (data?.separatorSlot) this.setSeparator(data.separatorSlot);
    if (data?.clearSlot) this.setClear(data.clearSlot);
    if (data?.nowSlot) this.setNow(data.nowSlot);
    if (data?.confirmSlot) this.setConfirm(data.confirmSlot);
  }

  setAttrs(attrs: OmitHTMLAttributes<"onChange">) {
    this.attrs = attrs;
    return this;
  }

  setProps(props: DatePickerProps) {
    this.props = props;
    return this;
  }

  setDateIcon(component: BaseComponentType) {
    this.dateIconSlot = component;
    return this;
  }

  setFooter(component: BaseComponentType) {
    this.footerSlot = component;
    return this;
  }

  setNextMonth(component: BaseComponentType) {
    this.nextMonthSlot = component;
    return this;
  }

  setNextYear(component: BaseComponentType) {
    this.nextYearSlot = component;
    return this;
  }

  setPrevMonth(component: BaseComponentType) {
    this.prevMonthSlot = component;
    return this;
  }

  setPrevYear(component: BaseComponentType) {
    this.prevYearSlot = component;
    return this;
  }

  setSeparator(component: BaseComponentType) {
    this.separatorSlot = component;
    return this;
  }

  setClear(component: (v?: DatePickerClearSlotProps) => BaseComponentType) {
    this.clearSlot = component;
    return this;
  }
  setNow(component: (v?: DatePickerNowSlotProps) => BaseComponentType) {
    this.nowSlot = component;
    return this;
  }
  setConfirm(component: (v?: DatePickerConfirmSlotProps) => BaseComponentType) {
    this.confirmSlot = component;
    return this;
  }

  focus() {
    this.domRef?.focus();
  }
  blur() {
    this.domRef?.blur();
  }

  create() {
    const getOtherSlot = () => {
      let slot: {
        clear?: (v: DatePickerClearSlotProps) => BaseComponentType;
        now?: (v: DatePickerNowSlotProps) => BaseComponentType;
        confirm?: (v: DatePickerConfirmSlotProps) => BaseComponentType;
      } = {
        clear: (v: DatePickerClearSlotProps) => getSlotsDom(this.clearSlot(v)),
        now: (v: DatePickerNowSlotProps) => getSlotsDom(this.nowSlot(v)),
        confirm: (v: DatePickerConfirmSlotProps) =>
          getSlotsDom(this.confirmSlot(v)),
      };
      if (
        ["date", "year", "quarterrange", "week"].includes(
          this.props.type as string
        )
      ) {
        delete slot.confirm;
      }

      if (
        ["daterange", "datetimerange", "monthrange", "yearrange"].includes(
          this.props.type as string
        )
      ) {
        delete slot.now;
      }

      return slot;
    };

    return (
      <NDatePicker
        ref={(el: HTMLElement) => {
          this.domRef = el as unknown as DatePickerInst;
        }}
        {...this.props}
        {...this.attrs}
      >
        {{
          "date-icon": getSlotsDom(this.dateIconSlot),
          footer: getSlotsDom(this.footerSlot),
          "next-month": getSlotsDom(this.nextMonthSlot),
          "next-year": getSlotsDom(this.nextYearSlot),
          "prev-month": getSlotsDom(this.prevMonthSlot),
          "prev-year": getSlotsDom(this.prevYearSlot),
          separator: getSlotsDom(this.separatorSlot),
          ...getOtherSlot(),
        }}
      </NDatePicker>
    );
  }
}
